package com.lifeverse.service;

import com.lifeverse.entity.HealthCheck;
import com.lifeverse.entity.enums.HealthStatus;
import com.lifeverse.repository.HealthCheckRepository;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.scheduling.annotation.Async;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.client.RestTemplate;

import java.time.LocalDateTime;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.concurrent.CompletableFuture;
import java.util.stream.Collectors;

/**
 * 健康检查服务
 */
@Service
@RequiredArgsConstructor
@Slf4j
@Transactional
public class HealthCheckService {

    private final HealthCheckRepository healthCheckRepository;
    private final AlertService alertService;
    private final RestTemplate restTemplate;

    /**
     * 注册健康检查
     */
    public HealthCheck registerHealthCheck(String serviceName, String checkName, String endpoint, 
                                         Integer intervalSeconds, Integer timeoutSeconds) {
        
        Optional<HealthCheck> existingCheck = healthCheckRepository
                .findByServiceNameAndCheckName(serviceName, checkName);
        
        if (existingCheck.isPresent()) {
            HealthCheck check = existingCheck.get();
            check.setEndpoint(endpoint);
            check.setIntervalSeconds(intervalSeconds);
            check.setTimeoutSeconds(timeoutSeconds);
            check.setEnabled(true);
            return healthCheckRepository.save(check);
        }

        HealthCheck healthCheck = new HealthCheck();
        healthCheck.setServiceName(serviceName);
        healthCheck.setCheckName(checkName);
        healthCheck.setEndpoint(endpoint);
        healthCheck.setIntervalSeconds(intervalSeconds != null ? intervalSeconds : 30);
        healthCheck.setTimeoutSeconds(timeoutSeconds != null ? timeoutSeconds : 10);
        healthCheck.setStatus(HealthStatus.UNKNOWN);
        healthCheck.setHealthScore(0.0);
        healthCheck.setEnabled(true);

        HealthCheck savedCheck = healthCheckRepository.save(healthCheck);
        log.info("注册健康检查: {} - {}", serviceName, checkName);

        return savedCheck;
    }

    /**
     * 执行单个健康检查
     */
    @Async
    public CompletableFuture<HealthCheck> performHealthCheck(Long healthCheckId) {
        Optional<HealthCheck> checkOpt = healthCheckRepository.findById(healthCheckId);
        if (checkOpt.isEmpty()) {
            return CompletableFuture.completedFuture(null);
        }

        HealthCheck healthCheck = checkOpt.get();
        if (!healthCheck.getEnabled()) {
            return CompletableFuture.completedFuture(healthCheck);
        }

        return performHealthCheckInternal(healthCheck);
    }

    /**
     * 执行健康检查的内部方法
     */
    private CompletableFuture<HealthCheck> performHealthCheckInternal(HealthCheck healthCheck) {
        long startTime = System.currentTimeMillis();
        
        try {
            // 执行HTTP健康检查
            ResponseEntity<String> response = restTemplate.getForEntity(
                    healthCheck.getEndpoint(), String.class);
            
            long responseTime = System.currentTimeMillis() - startTime;
            
            // 根据HTTP状态码判断健康状态
            HealthStatus status = determineHealthStatus(response.getStatusCode(), responseTime);
            double healthScore = calculateHealthScore(status, responseTime);
            
            healthCheck.updateResult(status, healthScore, responseTime, 
                    "HTTP " + response.getStatusCode().value());
            
            log.debug("健康检查完成: {} - {} - 状态: {} - 响应时间: {}ms", 
                    healthCheck.getServiceName(), healthCheck.getCheckName(), status, responseTime);

        } catch (Exception e) {
            long responseTime = System.currentTimeMillis() - startTime;
            healthCheck.setError("健康检查失败: " + e.getMessage());
            
            log.warn("健康检查失败: {} - {} - 错误: {}", 
                    healthCheck.getServiceName(), healthCheck.getCheckName(), e.getMessage());
            
            // 如果连续失败次数达到阈值，创建告警
            if (healthCheck.getConsecutiveFailures() >= 3) {
                createHealthCheckAlert(healthCheck);
            }
        }

        HealthCheck savedCheck = healthCheckRepository.save(healthCheck);
        return CompletableFuture.completedFuture(savedCheck);
    }

    /**
     * 根据HTTP状态码和响应时间确定健康状态
     */
    private HealthStatus determineHealthStatus(HttpStatus httpStatus, long responseTime) {
        if (!httpStatus.is2xxSuccessful()) {
            return HealthStatus.DOWN;
        }
        
        if (responseTime > 5000) { // 5秒以上
            return HealthStatus.CRITICAL;
        } else if (responseTime > 2000) { // 2秒以上
            return HealthStatus.UNHEALTHY;
        } else if (responseTime > 1000) { // 1秒以上
            return HealthStatus.WARNING;
        } else {
            return HealthStatus.HEALTHY;
        }
    }

    /**
     * 计算健康分数
     */
    private double calculateHealthScore(HealthStatus status, long responseTime) {
        double baseScore = status.getHealthScore();
        
        // 根据响应时间调整分数
        if (responseTime > 0) {
            double timeScore = Math.max(0, 1.0 - (responseTime / 10000.0)); // 10秒为最差
            return Math.min(baseScore, timeScore);
        }
        
        return baseScore;
    }

    /**
     * 创建健康检查告警
     */
    private void createHealthCheckAlert(HealthCheck healthCheck) {
        String alertName = "健康检查失败";
        String description = String.format("服务 %s 的健康检查 %s 连续失败 %d 次", 
                healthCheck.getServiceName(), healthCheck.getCheckName(), healthCheck.getConsecutiveFailures());
        
        Map<String, String> labels = Map.of(
                "service", healthCheck.getServiceName(),
                "check", healthCheck.getCheckName(),
                "endpoint", healthCheck.getEndpoint() != null ? healthCheck.getEndpoint() : ""
        );
        
        Map<String, String> annotations = Map.of(
                "consecutive_failures", healthCheck.getConsecutiveFailures().toString(),
                "last_error", healthCheck.getErrorMessage() != null ? healthCheck.getErrorMessage() : ""
        );

        alertService.createAlert(alertName, description, 
                com.lifeverse.entity.enums.AlertSeverity.ERROR,
                healthCheck.getServiceName(), "health_check_failure", 
                labels, annotations, null, null);
    }

    /**
     * 定时执行所有健康检查
     */
    @Scheduled(fixedRate = 30000) // 每30秒执行一次
    public void performScheduledHealthChecks() {
        LocalDateTime threshold = LocalDateTime.now().minusSeconds(30);
        List<HealthCheck> checksToPerform = healthCheckRepository.findServicesDueForCheck(threshold);
        
        log.debug("执行定时健康检查，待检查服务数: {}", checksToPerform.size());
        
        for (HealthCheck healthCheck : checksToPerform) {
            performHealthCheckInternal(healthCheck);
        }
    }

    /**
     * 获取服务健康状态
     */
    @Transactional(readOnly = true)
    public List<HealthCheck> getServiceHealthStatus(String serviceName) {
        return healthCheckRepository.findByServiceName(serviceName);
    }

    /**
     * 获取所有不健康的服务
     */
    @Transactional(readOnly = true)
    public List<HealthCheck> getUnhealthyServices() {
        return healthCheckRepository.findUnhealthyServices();
    }

    /**
     * 获取健康检查统计信息
     */
    @Transactional(readOnly = true)
    public Map<String, Object> getHealthStatistics() {
        Map<String, Object> statistics = new java.util.HashMap<>();

        // 按状态统计
        List<Object[]> statusCounts = healthCheckRepository.countByStatus();
        Map<String, Long> statusStats = statusCounts.stream()
                .collect(Collectors.toMap(
                        row -> ((HealthStatus) row[0]).name(),
                        row -> (Long) row[1]
                ));
        statistics.put("statusCounts", statusStats);

        // 按服务和状态统计
        List<Object[]> serviceStatusCounts = healthCheckRepository.countByServiceAndStatus();
        Map<String, Map<String, Long>> serviceStats = new java.util.HashMap<>();
        for (Object[] row : serviceStatusCounts) {
            String serviceName = (String) row[0];
            String status = ((HealthStatus) row[1]).name();
            Long count = (Long) row[2];
            
            serviceStats.computeIfAbsent(serviceName, k -> new java.util.HashMap<>())
                    .put(status, count);
        }
        statistics.put("serviceStatusCounts", serviceStats);

        // 平均响应时间
        LocalDateTime since = LocalDateTime.now().minusHours(24);
        List<Object[]> avgResponseTimes = healthCheckRepository.getAverageResponseTimeByService(since);
        Map<String, Double> responseTimeStats = avgResponseTimes.stream()
                .collect(Collectors.toMap(
                        row -> (String) row[0],
                        row -> (Double) row[1]
                ));
        statistics.put("averageResponseTimes", responseTimeStats);

        // 服务可用性
        List<Object[]> availability = healthCheckRepository.getServiceAvailability(since);
        Map<String, Double> availabilityStats = availability.stream()
                .collect(Collectors.toMap(
                        row -> (String) row[0],
                        row -> (Double) row[1]
                ));
        statistics.put("serviceAvailability", availabilityStats);

        return statistics;
    }

    /**
     * 启用/禁用健康检查
     */
    public HealthCheck toggleHealthCheck(Long healthCheckId, boolean enabled) {
        Optional<HealthCheck> checkOpt = healthCheckRepository.findById(healthCheckId);
        if (checkOpt.isEmpty()) {
            throw new RuntimeException("健康检查不存在: " + healthCheckId);
        }

        HealthCheck healthCheck = checkOpt.get();
        healthCheck.setEnabled(enabled);
        
        HealthCheck savedCheck = healthCheckRepository.save(healthCheck);
        log.info("健康检查状态更新: {} - {} - 启用: {}", 
                healthCheck.getServiceName(), healthCheck.getCheckName(), enabled);

        return savedCheck;
    }

    /**
     * 删除健康检查
     */
    public void deleteHealthCheck(Long healthCheckId) {
        Optional<HealthCheck> checkOpt = healthCheckRepository.findById(healthCheckId);
        if (checkOpt.isEmpty()) {
            throw new RuntimeException("健康检查不存在: " + healthCheckId);
        }

        HealthCheck healthCheck = checkOpt.get();
        healthCheckRepository.delete(healthCheck);
        log.info("删除健康检查: {} - {}", healthCheck.getServiceName(), healthCheck.getCheckName());
    }

    /**
     * 清理过期的健康检查记录
     */
    public void cleanupHealthCheckHistory(int daysToKeep) {
        LocalDateTime threshold = LocalDateTime.now().minusDays(daysToKeep);
        healthCheckRepository.deleteHealthChecksBefore(threshold);
        log.info("清理过期健康检查记录完成，保留天数: {}", daysToKeep);
    }

    /**
     * 获取服务健康趋势
     */
    @Transactional(readOnly = true)
    public List<Object[]> getServiceHealthTrend(String serviceName, int days) {
        LocalDateTime since = LocalDateTime.now().minusDays(days);
        return healthCheckRepository.getHealthTrendByService(serviceName, since);
    }

    /**
     * 获取整体健康趋势
     */
    @Transactional(readOnly = true)
    public List<Object[]> getOverallHealthTrend(int days) {
        LocalDateTime since = LocalDateTime.now().minusDays(days);
        return healthCheckRepository.getOverallHealthTrend(since);
    }
}